package com.venusj.ipersistence.sqlSession;

import com.venusj.ipersistence.config.BoundSql;
import com.venusj.ipersistence.pojo.Configuration;
import com.venusj.ipersistence.pojo.MappedStatement;
import com.venusj.ipersistence.utils.GenericTokenParser;
import com.venusj.ipersistence.utils.ParamterMapping;
import com.venusj.ipersistence.utils.ParamterMappingTokenHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zhangjh
 * @date 2020/10/15
 * @desc
 */
public class SimpleExecutor implements Executor {
    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement statement, Object... params) throws Exception {
        // 1、注册驱动获取链接
        Connection connection = configuration.getDataSource().getConnection();
        // 2、sql转换   原生jdbc占位符为？  现在变成#{}
        String sql = statement.getSql();
        BoundSql boundSql = getBoundSql(sql);

        // 3、获取预处理对象
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSql());

        // 4、设置参数
        // 获取参数全路径（反射获取属性值），和获取
        String paramterType = statement.getParamterType();

        Class<?> paramterTypeClass = getClassType(paramterType);
        List<ParamterMapping> paramterMappingList = boundSql.getParamterMappingList();
        for (int i=0; i< paramterMappingList.size(); i++) {
            ParamterMapping paramterMapping = paramterMappingList.get(i);
            String name = paramterMapping.getName();
            // 反射
            Field declaredField = paramterTypeClass.getDeclaredField(name);
            // 暴力访问
            declaredField.setAccessible(true);
            Object o = declaredField.get(params[0]);

            preparedStatement.setObject(i +1 , o);
        }
        // 5、执行sql
        ResultSet resultSet = preparedStatement.executeQuery();
        String resultType = statement.getResultType();
        Class<?> resultTypeClass = getClassType(resultType);
        List result = new ArrayList();
        while (resultSet.next()) {
            Object o = resultTypeClass.newInstance();
            // 元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            for(int i =1; i<=metaData.getColumnCount(); i++)
            {
                String columnName = metaData.getColumnName(i);

                Object value = resultSet.getObject(columnName);

                // 利用反射或者内省  根据数据库和实体类的映射关系，完成封装

                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(o, value);
            }
            result.add(o);
        }

        // 6、返回封装对象
        return result;
    }

    private Class<?> getClassType(String paramterType) throws ClassNotFoundException {

        if(paramterType != null)
        {
            Class<?> aClass = Class.forName(paramterType);
            return aClass;
        }

        return null;
    }

    /**
     * 标记处理占位符sql
     * @param sql
     * @return
     */
    private BoundSql getBoundSql(String sql){
        ParamterMappingTokenHandler paramterMappingTokenHandler = new ParamterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", paramterMappingTokenHandler);

        // 解析#{}里面的参数
        String parseSql = genericTokenParser.parse(sql);
        List<ParamterMapping> paramterMappingList = paramterMappingTokenHandler.getParamterMappingList();
        BoundSql boundSql = new BoundSql(parseSql, paramterMappingList);
        return boundSql;
    }
}
